package publish;

import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.Player;
import javax.media.RealizeCompleteEvent;
import javax.media.control.BufferControl;
import javax.media.protocol.DataSource;
import javax.media.rtp.*;
import javax.media.rtp.event.*;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.InetAddress;

/**
 * Created by RXJ on 2018/2/5.
 */
// 头一段时间做jmf程序，要把截获的视频流，潜入到网页中，并播放；
// 在网上找了很多例子，是弹出 frame 框形式的，没有做成嵌入到 applet 里面，
// 自己做了一个嵌入到 applet 里面的。也就是把播放器嵌入到 applet 里面，
// 而不是弹出一个 Frame 框，并且定义了两个按钮；一个启动，一个停止；以下是源码；
// 解压码是:xuedijiujiu 这是个客户端 applet 程序程序，实现视频的接受和播放；
// 服务器端可以用JMStudio来辅助调试； 程序仅供研究
public class AudioVideoReceiver extends Applet implements ControllerListener,
        ReceiveStreamListener, SessionListener, Runnable {
    private static final long serialVersionUID = -5570418604643606114L;

    RTPManager rtpManager = null;
    Player player = null;
    boolean dataReceived = false; // 是否接收到数据的标志
    Object dataSync = new Object(); // 专门用于锁的对象

    Component component1;
    Component component2;

    Button btnStartVideo;
    Button btnStopVideo;

    TextField tfServerIP;

    public void init() {
        this.setLayout(null);
        // 添加两个按钮，并注册相应的事件！
        btnStartVideo = new Button("start");
        btnStartVideo.setBounds(10, 350, 80, 20);
        btnStartVideo.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (player == null) {
                    Thread t = new Thread(AudioVideoReceiver.this);
                    t.start();
                    System.out.println("thread start");
                }
            }
        });
        this.add(btnStartVideo);
        // -----------------------------------------------------
        btnStopVideo = new Button("stop");
        btnStopVideo.setBounds(150, 350, 80, 20);
        btnStopVideo.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (player != null) {
                    remove(component1);
                    remove(component2);
                }
                stopVideo();
                System.out.println("thread stop");
            }
        });
        this.add(btnStopVideo);
        this.setSize(350, 380);
    }

    protected boolean initialize() {
        try {
            rtpManager = RTPManager.newInstance();  // 为每一个RTP会话产生一个RTP管理器
            rtpManager.addSessionListener(this);    // 添加会话监听
            rtpManager.addReceiveStreamListener(this); // 添加接收到数据的监听

            // 特别注意的地方：不能将本地地址设置为“127.0.0.1”，必须要实际的ip地址！！
//          InetAddress ipAddress = InetAddress.getByName("224.224.123.123");   // 接收广播
            InetAddress ipAddress = InetAddress.getByName("192.168.1.218"); // 接收单播

            SessionAddress localAddress = null;
            SessionAddress targetAddress = null;
            // 说明：当 ip 地址为“224.224.123.123”的时候，属于组播(亦称广播，能被多个接收端接收)
            //      当 ip 地址为“110.52.206.144”的时候，属于单播，会自动跳到 else 分支中去！！
            if (ipAddress.isMulticastAddress()) { // 对于组播，本地和目的地的IP地址相同，均采用组播地址
                System.out.println("is MulticastAddress()");
                localAddress = new SessionAddress(ipAddress, 22222);
                targetAddress = new SessionAddress(ipAddress, 22222);
            } else {
                System.out.println("is Not MulticastAddress()");
                localAddress = new SessionAddress(InetAddress.getLocalHost(), 8888); // 用本机IP地址和端口号构造源会话地址
                targetAddress = new SessionAddress(ipAddress, 3000); // 用目的机（发送端）的IP地址和端口号构造目的会话地址
            }

            rtpManager.initialize(localAddress); // 将本机会话地址给RTP管理器
            BufferControl bc = (BufferControl)rtpManager.getControl("javax.media.control.BufferControl");
            if (bc != null) {
                bc.setBufferLength(350); // 设置缓冲区大小（也可以使用其他值）
            }

            rtpManager.addTarget(targetAddress); // 加入目的会话地址
        } catch (Exception e) {
            System.err.println("Cannot create the RTP Session: " + e.getMessage());
            return false;
        }

        // 等待数据到达
        long then = System.currentTimeMillis();
        long waitingPeriod = 6000; // 最多等待60秒
        try {
            synchronized (dataSync) {
                // 等待上面所设定的时间
                while (!dataReceived && System.currentTimeMillis() - then < waitingPeriod) {
                    if (!dataReceived) {
                        System.err.println("  - Waiting for RTP data to arrive...");
                    }
                    dataSync.wait(1000);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (!dataReceived) { // 在设定的时间内没有等到数据
            System.err.println("No RTP data was received.");
            player.close();
            player.stop();
            return false;
        }
        return true;
    }

    public void start() {
        if (player != null) {
            player.start();
        }
    }

    public void stopVideo() {
        if (player != null) {
            player.close();
            player = null;
        }
        if (rtpManager != null) {
            rtpManager.removeTargets("Closing session from RTPReceive");
            rtpManager.dispose(); // 关闭RTP会话管理器
            rtpManager = null;
        }
    }

    public void destroy() {
        if (player != null) {
            player.close();
            player = null;
        }
        if (rtpManager != null) {
            rtpManager.removeTargets("Closing session from RTPReceive");
            rtpManager.dispose(); // 关闭RTP会话管理器
            rtpManager = null;
        }
    }

    public synchronized void controllerUpdate(ControllerEvent event) {
        if (event instanceof RealizeCompleteEvent) {
            if ((component1 = player.getVisualComponent()) != null) {
                this.add(component1);
            }
            component1.setBounds(10, 10, 300, 300);
            if ((component2 = player.getControlPanelComponent()) != null) {
                this.add(component2);
            }
            component2.setBounds(10, 310, 300, 20);
            validate();
            System.out.println("palyer");
        }
    }

    public synchronized void update(ReceiveStreamEvent evt) {
        @SuppressWarnings("unused")
        RTPManager mgr = (RTPManager) evt.getSource();
        Participant participant = evt.getParticipant(); // 得到加入者（发送者）
        ReceiveStream stream = evt.getReceiveStream(); // 得到接收到的数据流

        if (evt instanceof NewReceiveStreamEvent) { // 接收到新的数据流
            try {
                stream = ((NewReceiveStreamEvent) evt).getReceiveStream(); // 得到新数据流
                DataSource ds = stream.getDataSource(); // 得到数据源

                RTPControl ctl = (RTPControl) ds
                        .getControl("javax.media.rtp.RTPControl"); // 得到RTP控制器
                if (ctl != null) {
                    System.err.println("Recevied new RTP stream: " + ctl.getFormat()); // 得到接收数据的格式
                } else {
                    System.err.println("Recevied new RTP stream");
                }
                if (participant == null) {
                    System.err.println("The sender of this stream had yet to be identified.");
                } else {
                    System.err.println("The stream comes from: " + participant.getCNAME());
                }
                player = javax.media.Manager.createPlayer(ds); // 通过数据源构造一个媒体播放器
                if (player == null) {
                    return;
                }
                player.addControllerListener(this); // 给播放器添加控制器监听
                player.realize();
                synchronized (dataSync) {
                    dataReceived = true;
                    dataSync.notifyAll();
                }
            } catch (Exception e) {
                System.err.println("NewReceiveStreamEvent exception" + e.getMessage());
                return;
            }
        } else if (evt instanceof StreamMappedEvent) { // 数据流映射事件
            if (stream != null && stream.getDataSource() != null) {
                DataSource ds = stream.getDataSource();
                RTPControl ctl = (RTPControl)ds.getControl("javax.media.rtp.RTPControl");
                System.err.println("  - The previously unidentified stream ");
                if (ctl != null) {
                    System.err.println("      " + ctl.getFormat()); // 得到格式
                }
                System.err.println("      had now been identified as sent by: "
                        + participant.getCNAME());
            }
        } else if (evt instanceof ByeEvent) { // 数据接收完毕
            System.err.println("  - Got /'bye/' from: " + participant.getCNAME());

            if (player != null) {
                player.close(); // 关闭播放窗口
            }
        }
    }

    public synchronized void update(SessionEvent evt) {
        if (evt instanceof NewParticipantEvent) {
            Participant p = ((NewParticipantEvent) evt).getParticipant();
            System.err.println("  - A new participant had just joined: "
                    + p.getCNAME());
        }
    }

    public void run() {
        this.initialize();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        player.start();
    }
}